<template>
	<a-modal v-bind="options" class="bill-handle-dialog">
		<div class="address">房源地址：{{ detail.fullHouseAddress }}</div>
		<div class="tips">
			<div>
				<a-typography-text type="secondary">应收(付)日期</a-typography-text>
				<strong>{{ formatDate(detail.predictTime) }}</strong>
			</div>
			<a-divider type="vertical" />
			<div>
				<a-typography-text type="secondary">已收(付)</a-typography-text>
				<strong v-color="{color: detail.occurredMoney < 0 ? 'danger' : 'primary'}">
					{{ detail.occurredMoney.toLocaleString() }} 元
				</strong>
			</div>
			<a-divider type="vertical" />
			<div>
				<a-typography-text type="secondary">待收(付)</a-typography-text>
				<strong v-color="{color: detail.notOccurredMoney < 0 ? 'danger' : 'primary'}">
					{{ (detail.notOccurredMoney - totalCouponDiscountAmount).toLocaleString() }} 元
				</strong>
			</div>
		</div>
		<vxe-grid ref="grid" v-bind="gridOptions" :data="detail.billDetailList" :loading="loadings.detail">
			<template #feeSubjectValue="{row}">
				{{ row.feeSubjectValue }}：{{ row.attributionType === 1 ? '企业承担' : '个人承担' }}
			</template>
			<template #originalMoney="{row}">
				<span v-color="{color: amountColor(row)}">
					{{ amountSymbol(row) }}
				</span>
				{{ row.originalMoney }}
				/
				{{ row.occurredMoney }}
			</template>
			<template #notOccurredMoney="{row}">
				<span v-color="{color: amountColor(row)}">
					{{ amountSymbol(row) }}
				</span>
				{{ row.notOccurredMoney }}
			</template>

			<template #occurredMoney="{row}">
				<template v-if="row.notOccurredMoney === 0">
					<span v-color="{color: amountColor(row)}">
						{{ amountSymbol(row) }}
					</span>
					{{ row.occurredMoney }}
				</template>
				<a-input-number
					v-else
					v-model:value="row.money"
					:min="0"
					:max="row.notOccurredMoney"
					:precision="2"
					placeholder="请输入"
					style="width: 100%"
					:disabled="paidInput">
					<template #prefix>
						<span v-color="{color: amountColor(row)}">
							{{ amountSymbol(row) }}
						</span>
					</template>
				</a-input-number>
			</template>

			<template #coupon="{row}">
				<span style="margin-right: 5px" v-if="row.couponNums !== 0">{{ row.couponNums }}张/{{ row.couponDiscountAmount }}元</span>
				<span style="cursor: pointer" v-if="couponList.includes(row.feeSubjectId) && 1 !== row.isOccur">
					<PlusCircleTwoTone style="margin-right: 5px" @click="chooseCoupon(row)" />
					<CloseCircleTwoTone :twoToneColor="'red'" @click="clearCoupon(row)" v-if="row.couponNums" />
				</span>
				<span v-else style="cursor: pointer; margin-right: 5px">
					<PlusCircleOutlined :style="{color: '#999'}" />
				</span>
			</template>

			<template #action="{row}">
				<template v-if="row.notOccurredMoney === 0 || row.notOccurredMoney === row.money">暂无余额</template>
				<template v-else>
					余
					<span v-color="{color: amountColor(row)}">
						{{ amountSymbol(row) }}
					</span>
					{{ (row.notOccurredMoney - row.money).toFixed(2) }}元
				</template>
				<template v-if="row.notOccurredMoney > row.money">
					<a-select
						v-model:value="row.solution"
						:options="leftOptions"
						style="width: 100px; margin-left: 20px; text-align: left" />
				</template>
			</template>

			<template #bottom>
				<vxe-toolbar perfect>
					<template #buttons>
						<div style="display: flex; justify-content: space-between">
							<span style="margin-right: auto">
								本次已收(付)总额：
								<span v-color="{color: total.paidAmount >= 0 ? 'primary' : 'error'}">
									{{ total.paidAmount.toLocaleString() }}
								</span>
								&nbsp;元，优惠
								<span v-color="{color: total.paidAmount >= 0 ? 'primary' : 'error'}">
									{{ totalCouponDiscountAmount?.toFixed(2) || 0 }}
								</span>
								元， 余&nbsp;
								<span v-color="{color: total.unpaidAmount >= 0 ? 'primary' : 'error'}">
									{{ total.unpaidAmount.toLocaleString() }}
								</span>
								&nbsp;元
							</span>
							<span style="margin-left: 42px">
								可用优惠券
								<span v-color="{color: 'primary'}">{{ totalCouponNums || 0 }}</span>
								张
							</span>
						</div>
					</template>
					<template #tools>
						<template v-if="total.leftAmount != 0">
							<span v-color="{color: 'danger'}">*</span>
							&nbsp;&nbsp;剩余款项提醒：
							<a-date-picker v-model:value="entity.remindDate" :value-format="DATE_FORMAT.DATE" />
						</template>
					</template>
				</vxe-toolbar>
			</template>
		</vxe-grid>
		<a-form :model="entity" ref="formRef">
			<a-typography-text strong>
				<blockquote>支付详情</blockquote>
			</a-typography-text>
			<a-row :gutter="24">
				<a-col :span="8">
					<a-form-item name="practicalTime" label="支付时间" :rules="[{required: true, message: '请选择支付时间'}]">
						<a-date-picker
							v-model:value="entity.practicalTime"
							show-time
							:value-format="DATE_FORMAT.DATETIME"
							:disabled-date="disabledDate"
							@change="changeDateTime" />
					</a-form-item>
				</a-col>
				<a-col :span="16">
					<a-form-item name="paymentMethod" label="支付方式" :rules="[{required: true, message: '请选择支付方式'}]">
						<a-input-group compact class="display-flex">
							<a-form-item-rest>
								<a-select
									v-model:value="entity.paymentMethod"
									:options="paymentMethods"
									:field-names="{label: 'name', value: 'id'}"
									placeholder="支付方式"
									style="width: 120px"
									@change="paymentChange" />
								<a-input v-model:value="entity.paymentAccount" placeholder="请输入客户账号" style="flex: 1" />
							</a-form-item-rest>
						</a-input-group>
					</a-form-item>
				</a-col>
			</a-row>
			<a-form-item label="支付流水号" name="bankStatement">
				<a-input v-model:value="entity.bankStatement" show-count :maxlength="100" placeholder="请输入支付流水号" />
			</a-form-item>
			<a-form-item label="支付备注" name="comment">
				<a-textarea v-model:value="entity.comment" show-count :maxlength="200" placeholder="请输入支付备注" />
			</a-form-item>
			<a-form-item label="支付凭证" name="voucherAttach">
				<file-upload v-model:files="files" show-qr-code show-tips />
			</a-form-item>
		</a-form>
	</a-modal>
	<coupon-dialog
		v-model:visible="dialogOption.visible"
		@success="updateList"
		:currentRow="currentData.row"
		:checkList="currentData.checkList"
		:checkCouponListExceptSelf="checkCouponListExceptSelf"></coupon-dialog>
</template>

<script setup lang="ts">
	import {computed, reactive, ref, toRef, watch, createVNode} from 'vue'
	import {FormInstance, message, Modal} from 'ant-design-vue'
	import {VxeGridProps} from 'vxe-table'
	import SettingApi from 'yuxin-base/src/api/setting-api'
	import {financeBillAffirmFinance, getFinanceByBillId, getFinanceByBillIdView, activityDistributeList} from '@/api/bill'
	import {Img} from 'yuxin-base/src/types'
	import {DIC_PID_MAP} from 'yuxin-base/src/constant'
	import FileUpload from '@/components/common/file-upload.vue'
	import DATE_FORMAT, {nowDateTime, formatDate} from 'yuxin-base/src/utils/date'
	import {BillDeatil} from '@/interface/bill'
	import {amountColor, amountSymbol} from 'yuxin-base/src/utils'
	import XEUtils from 'xe-utils'
	import dayjs, {Dayjs} from 'dayjs'
	import {PlusCircleTwoTone, CloseCircleTwoTone, PlusCircleOutlined, ExclamationCircleOutlined} from '@ant-design/icons-vue'
	import couponDialog from './coupon-dialog'

	const props = defineProps<{
		// 账单id
		id?: string
		visible: boolean
	}>()

	const loadings = reactive({
		detail: false
	})
	const files = ref<Img[]>([])
	const detail = ref<BillDeatil>({
		occurredMoney: 0,
		notOccurredMoney: 0
	})
	const emits = defineEmits(['update:visible', 'close'])
	const options = reactive({
		title: '账单处理',
		width: 1200,
		centered: true,
		maskClosable: false,
		destroyOnClose: true,
		confirmLoading: false,
		visible: toRef(props, 'visible'),
		onOk() {
			submit()
		},
		onCancel: () => close()
	})

	const close = () => {
		emits('update:visible', false)
		setTimeout(() => emits('close'), 100)
		files.value = []
		detail.value = {occurredMoney: 0, notOccurredMoney: 0}
		entity.detailList = []
		entity.bankStatement = null
		entity.paymentAccount = null
		formRef.value?.resetFields()
		currentData.row = {}
		currentData.checkList = []
		currentData.checkObj = {}
		currentData.checkIdObj = {}
	}
	const leftOptions = [
		{
			value: 1,
			label: '继续提醒'
		}
	]

	const entity = reactive<any>({
		// 银行流水
		bankStatement: null,
		// 账单ID
		billId: null,
		// 费用备注
		comment: null,
		// 收付款收支集合
		detailList: [],
		// 收付款方式途径【字典】
		paymentMethod: null,
		// 收付款账户
		paymentAccount: null,
		// 实收付时间
		practicalTime: null,
		// 继续提醒时间
		remindDate: null,
		// 支付凭证
		voucherAttach: null,
		// 优惠券id
		distributeCouponIds: null
	})
	const currentData = reactive<{
		row: any
		checkList: any
		checkObj: any
		checkIdObj: any
	}>({
		row: null,
		checkList: [],
		checkObj: {},
		checkIdObj: {}
	})
	const grid = ref()
	const gridOptions = reactive<VxeGridProps>({
		size: 'small',
		height: 300,
		showOverflow: true,
		rowConfig: {
			isHover: true
		},
		columns: [
			{
				field: 'feeSubjectValue',
				title: '费用科目',
				minWidth: 200,
				slots: {
					default: 'feeSubjectValue'
				}
			},
			{
				title: '应收(付)/已收(付)',
				minWidth: 200,
				slots: {
					default: 'originalMoney'
				}
			},
			{
				title: '待收(付)',
				minWidth: 160,
				slots: {
					default: 'notOccurredMoney'
				}
			},
			{
				title: '已收(付)',
				minWidth: 160,
				slots: {
					default: 'occurredMoney'
				}
			},
			{
				title: '优惠券',
				minWidth: 140,
				align: 'center',
				slots: {
					default: 'coupon'
				}
			},
			{
				title: '余额处理',
				width: 260,
				align: 'center',
				slots: {
					default: 'action'
				}
			}
		]
	})

	// 计算优惠后的已收付金额

	// 计算页面金额项
	const total = computed(() => {
		// 已收付
		let paidAmount = 0
		// 待收付
		let unpaidAmount = 0
		// 总剩余款
		let leftAmount = 0

		const bills = detail.value.billDetailList || []

		for (let bill of bills) {
			const direction = bill.feeDirection === 1 ? 1 : -1
			paidAmount += XEUtils.multiply(bill.money, direction)
			unpaidAmount += XEUtils.multiply(XEUtils.subtract(bill.notOccurredMoney, bill.money), direction)
			leftAmount = unpaidAmount

			// 剩余款项减去免收
			if (bill.solution === 2) {
				leftAmount -= XEUtils.subtract(bill.notOccurredMoney, bill.money)
			}
		}

		return {
			paidAmount: Number(paidAmount.toFixed(2)),
			unpaidAmount: Number(unpaidAmount.toFixed(2)),
			leftAmount: Number(leftAmount.toFixed(2))
		}
	})

	const disabledDate = (current: Dayjs) => {
		return current && current > dayjs()
	}

	const formRef = ref<FormInstance>()

	// 优惠总金额
	const totalCouponDiscountAmount = ref(0)
	// 优惠券总数量
	const totalCouponNums = ref(0)
	const couponList = ref<Array<string>>([])

	const feeSubjectIdList = ref([])
	// 付款方式
	const paymentMethods = ref<any[]>([])
	// 已付输入框
	const paidInput = ref(false)
	const dialogOption = reactive({
		visible: false,
		source: []
	})

	// 用了优惠券后展示最新的账单预览
	const getNewBillPreview = () => {
		const params: any = {
			billDetailCouponItems: [],
			contractId: detail.value.bizId,
			billId: props.id
		}

		for (const key in currentData.checkIdObj) {
			params.billDetailCouponItems.push({
				billDetailId: key,
				distributeCouponIds: currentData.checkIdObj[key]
			})
		}

		loadings.detail = true
		getFinanceByBillIdView(params)
			.then(({data}) => {
				const billDetailList = data.billDetailList || []
				for (let item of billDetailList) {
					item.solution = 1
					item.beginMoney = item.originalMoney
					//当前的应收=原本的应收-该项全部的优惠金额，同下
					item.money = XEUtils.subtract(item.notOccurredMoney, item.couponDiscountAmount)
					item.notOccurredMoney = XEUtils.subtract(item.notOccurredMoney, item.couponDiscountAmount)
					item.originalMoney = XEUtils.subtract(item.originalMoney, item.couponDiscountAmount)
				}

				detail.value = data
				totalCouponDiscountAmount.value = data.totalCouponDiscountAmount
			})
			.finally(() => (loadings.detail = false))
	}

	watch(
		() => props.visible,
		newVal => {
			if (newVal && props.id) {
				// 默认支付时间为当前时间
				entity.practicalTime = nowDateTime()

				SettingApi.getDicListByPid(DIC_PID_MAP['PAYMENTMETHOD@PAYMENTMETHOD']).then(({data}) => {
					paymentMethods.value = data
				})

				loadings.detail = true
				getFinanceByBillId(props.id)
					.then(({data}) => {
						const {billDetailList = []} = data
						feeSubjectIdList.value = data.billDetailList.map(item => {
							return item.feeSubjectId
						})
						for (let item of billDetailList) {
							item.solution = 1
							item.money = item.notOccurredMoney
							item.bizId = data.bizId
							item.beginMoney = item.originalMoney
						}

						detail.value = data
						totalCouponDiscountAmount.value = data.totalCouponDiscountAmount

						const dataInfo = reactive<any>({
							current: 1,
							size: 20,
							feeSubjectIds: feeSubjectIdList.value,
							contractId: data.bizId,
							phone: data.payerPhone
						})
						// 可使用优惠券
						activityDistributeList(dataInfo).then(res => {
							// 可使用优惠券的数量
							totalCouponNums.value = res.data.enableUseSize
							// 过滤出可使用优惠券的费用ID
							couponList.value = res.data.couponRenterList
								.filter(item => {
									return item.isEnableUse === 1
								})
								.map(item => {
									return item.feeSubjectId
								})
						})
					})
					.finally(() => (loadings.detail = false))
			}
		}
	)

	// 除了当前点击的以外别的账单选中的账单列表
	const checkCouponListExceptSelf = ref<Array<string>>([])
	// 添加优惠券弹窗
	const chooseCoupon = row => {
		currentData.row = row

		checkCouponListExceptSelf.value = Object.keys(currentData.checkIdObj)
			.filter(i => i !== row.id)
			.reduce((prev, curr) => {
				return [...prev, ...currentData.checkIdObj[curr]]
			}, [] as Array<string>)

		currentData.checkList = currentData.checkObj[currentData.row.id] || []
		currentData.row.phone = detail.value.payerPhone

		dialogOption.visible = true
	}

	// 获取最新账单处理信息
	const updateList = (e: boolean, checkListInfo: any) => {
		const {key, list, ids} = checkListInfo
		currentData.checkObj[key] = list
		currentData.checkIdObj[key] = ids

		getNewBillPreview()
	}

	// 选择优惠券抵扣判断
	const paymentChange = e => {
		const tagList = paymentMethods.value.find(item => item.id === e)
		if (tagList.tag === 'COUPON_DEDUCTION_FEE' && total.value.paidAmount !== 0) {
			entity.paymentMethod = null
			return message.error('优惠劵抵扣支付方式不可用，请选择优惠劵抵扣所有金额后再次选择')
		}
	}

	// 清除优惠券选择
	const clearCoupon = (row: any) => {
		Modal.confirm({
			title: '提示',
			centered: true,
			icon: createVNode(ExclamationCircleOutlined),
			content: '确定要删除吗？',
			onOk() {
				currentData.checkIdObj[row.id] = []
				currentData.checkObj[row.id] = []

				getNewBillPreview()
				totalCouponDiscountAmount.value = 0
			}
		})
	}

	// 日期变化时触发
	const changeDateTime = (date: any) => {
		if (dayjs(date).isAfter(nowDateTime())) {
			message.warning('设定超过当前时间')
			entity.practicalTime = nowDateTime()
		}
	}

	const submit = () => {
		let detailList: any[] = detail.value.billDetailList
			?.filter(o => o.isOccur === 0)
			.map(o => ({
				money: o.money,
				billDetailId: o.id,
				distributeCouponIds: currentData.checkIdObj[o.id] || [],
				solution: o.solution
			})) as []

		const allCoupon = detailList.reduce((prev, curr) => {
			return [...prev, ...curr.distributeCouponIds]
		}, [])

		const amount = XEUtils.sum(detailList, 'money') as number
		// 如果没有使用优惠券而且总金额为0的时候不允许提交
		if (!allCoupon.length && !amount) {
			return message.error('支付总金额不能为0')
		}

		if (!entity.remindDate && total.value.leftAmount !== 0) {
			return message.error('请选择剩余款项提醒日期')
		}

		formRef.value?.validate().then(() => {
			entity.billId = props.id
			entity.detailList = detailList
			entity.voucherAttach = files.value.map(o => o.id).join()

			options.confirmLoading = true

			financeBillAffirmFinance(entity)
				.then(() => {
					message.success('操作成功')
					options.onCancel()
					if (allCoupon.length) {
						paidInput.value = true
					}
				})
				.finally(() => (options.confirmLoading = false))
		})
	}
</script>

<style lang="less">
	.bill-handle-dialog {
		.ant-modal-body {
			overflow: auto;
			min-height: 600px;
			max-height: 900px;
			padding: 0 16px;

			.ant-form-item-label {
				width: 120px;
			}
		}

		.address {
			padding: 12px 0;
			font-weight: bold;
		}

		.tips {
			display: flex;
			background: #e5efff;
			padding: 8px 12px;
			align-items: center;

			> div:not(.ant-divider) {
				flex: 1;
				display: flex;
				justify-content: space-between;
			}
		}
	}
</style>
